package pro.ticktock.tools.mbconv;

import org.apache.commons.io.Charsets;

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by lambert on 2017/5/28.
 */
public class Pass2 extends AbstractPass{

  private Set<String> titleSetEn;
  private Set<String> titleSetCh;

  public Pass2(String origSrcFileName, String srcFileName) throws IOException, URISyntaxException {
    super(origSrcFileName, srcFileName);
    titleSetCh = new HashSet<>();
    titleSetEn = new HashSet<>();
    Files.readAllLines(Paths.get(Pass2.class.getResource("/sptitles").toURI()), Charsets.UTF_8)
            .stream()
            .forEach(line -> {
              line = line.trim();
              if (line.length() == 0) return;
              int sepIdx = line.indexOf('#');
              if (sepIdx < 0)
                titleSetCh.add(line);
              else {
                if (sepIdx > 0)
                  titleSetCh.add(line.substring(0, sepIdx));
                if (line.length() > sepIdx + 1)
                  titleSetEn.add(line.substring(sepIdx + 1));
              }
            });
  }

  public static final String CH_TITLE_MARK = "###CH_TITLE###";
  public static final String EN_TITLE_MARK = "###EN_TITLE###";
  public static final String CH_ARTIST_MARK = "###CH_ARTIST###";
  public static final String EN_ARTIST_MARK = "###EN_ARTIST###";

  Pattern leadingSpace = Pattern.compile("(^[ \\t　]{2,})[^\\s　]+");
  StringBuffer para = new StringBuffer();

  private enum TitleCheck {
    NORMAL, CN_TITLE_FOUND, CN_TITLE_CONT, EN_TITLE_FOUND, EN_TITLE_CONT
  }

  StringBuffer matched = null;
  TitleCheck matchState = TitleCheck.NORMAL; //1 for cn-beginning, 2 for extension, 3 for en-beginning, 4 for en-extension


  @Override
  protected void doProcess() throws IOException {
    Pattern titlePattern = Pattern.compile("^[\\s]*([^，。,]+)[：:]([^，。,]+)[\\s]*$");
    Pattern cnChars = Pattern.compile("[\u4e00-\u9fa5]");
    Pattern titleCont = Pattern.compile("^[\\s]*([^。：:]+)[\\s]*$");
    Pattern peopleName = Pattern.compile("^[\\s]*([^。:：，、？0-9]+)[\\s]*$");

    String line;
    while ((line = srcReader.readLine()) != null) {
      //people check
      if (matchState == TitleCheck.NORMAL) {
        String cnName = null;
        String enName = null;
        String firstLine = null;
        Matcher m = peopleName.matcher(line);
        if (m.find()) {
          if (cnChars.matcher(line).find()) {
            cnName = trim(line);
            firstLine = line;
            line = srcReader.readLine();
            if (line != null) {
              if (peopleName.matcher(line).find() && !cnChars.matcher(line).find()) {
                enName = trim(line);
              }
            }
          }
        }

        if (cnName != null && enName != null) {
          finishPara();
          resultWriter.append(CH_ARTIST_MARK + cnName + "\n");
          resultWriter.append(EN_ARTIST_MARK + enName + "\n");
          logWriter.append("Found artist: " + cnName + "/" + enName + "\n");

          continue;
        } else if (cnName != null) {
          processNormalStateLine(firstLine);
          if (line == null) break;
        } else {
          //continue process
        }
      }

      if (titleSetCh.contains(trim(line))) {
        finishPara();
        finishTitle(CH_TITLE_MARK + trim(line));
        continue;
      } else if (titleSetEn.contains(trim(line))) {
        finishTitle(EN_TITLE_MARK + trim(line));
        continue;
      }

      switch (matchState) {
        case NORMAL:
          Matcher m1 = titlePattern.matcher(line);
          if (m1.find()) {
            Matcher m2 = cnChars.matcher(line); //has chinese chars
            if (m2.find()) {
              matchState = TitleCheck.CN_TITLE_FOUND;
              matched = new StringBuffer();
              matched.append(line);
            }
          } else {
            matchState = TitleCheck.NORMAL;
          }
          break;
        case CN_TITLE_FOUND:
          Matcher m2 = cnChars.matcher(line.replace('：', ':'));
          if (m2.find()) {
            if (titleCont.matcher(line).find()) {
              matched.append(line);
            } else { //unexpected chinese
              matchState = TitleCheck.NORMAL;
            }
            break;
          } else {
            matchState = TitleCheck.CN_TITLE_CONT;
            //fall through 2 NOW
          }
        case CN_TITLE_CONT:
          m1 = titlePattern.matcher(line);
          if (m1.find()) {
            matchState = TitleCheck.EN_TITLE_FOUND;
            matched.append("\n" + line);
          } else {
            matchState = TitleCheck.NORMAL;
          }
          break;
        case EN_TITLE_FOUND:
          if (titleCont.matcher(line).find() && !cnChars.matcher(line.replace('：', ':')).find()) {
            matchState = TitleCheck.EN_TITLE_CONT;
            matched.append(" " + line);
            break;
          } else {
            //fall through to cont.
          }
        case EN_TITLE_CONT:
          if (titleCont.matcher(line).find() && !cnChars.matcher(line.replace('：', ':')).find()) {
            matched.append(" " + line);
          } else {
            finishPara();
            String[] rows = matched.toString().split("\\n");
            finishTitle(CH_TITLE_MARK + trim(rows[0]));
            finishTitle(EN_TITLE_MARK + trim(rows[1]));
            matched = null;
            matchState = TitleCheck.NORMAL;
            titleCount++;
          }
          break;
      }
      if (matchState == TitleCheck.NORMAL) {
        processNormalStateLine(line);
      }
    }

    if (para.length() > 0) {
      finishPara();
    }
  }

  void processNormalStateLine(String line) throws IOException {
    if (matched != null) {
      for (String aline : matched.toString().split("\\n")) {
        processParagraphLine(aline);
      }
    }
    processParagraphLine(line);
    matched = null;
  }


  void processParagraphLine(String line) throws IOException {
    if (line == null || line.trim().length() == 0) {
      return;
    }
    Matcher m = leadingSpace.matcher(line);
    if (m.find()) {
      if (para.length() > 0) {
        finishPara();
      }
      para.append("　　" + trim(line));
    } else {
      String tline = trim(line);
      if (para.length() > 1 && para.charAt(para.length() - 1) == '-') { //removed last dash in case conti-nue
        char prech = para.charAt(para.length() - 2);
        if ((prech >= 'a' && prech <= 'z')
            || (prech >= 'A' && prech <= 'Z')) {
          char ch = tline.charAt(0);
          if ((ch >= 'a' && ch <= 'z')
                  || (ch >= 'A' && ch <= 'Z')) {
            para.deleteCharAt(para.length() - 1);
            logWriter.append("Removed dash in the end of line: " + prech + "-" + ch + "\n");
            lineEndDash++;
          }
        }
      }
      para.append(tline);
    }
  }

  Pattern badNoInEnTitle = Pattern.compile("(N[o0])(\\d+)");
  private void finishTitle(String title) throws IOException {
    if (title.startsWith(EN_TITLE_MARK)) {
      Matcher m = badNoInEnTitle.matcher(title);
      if (m.find()) {
        title = title.substring(0, m.start(1)) + "No." + title.substring(m.end(1));
        logWriter.write("Bad No1 in title, replaced " + m.group(0) + " with No." + m.group(2) + "\n");
      }
    }
    try {
      resultWriter.append(title.replace('．', '.') + "\n");
    } catch (IOException e) {
    }
  }

  private void finishPara() {
    if (para.length() == 0) return;

    try {
      char ch = para.charAt(para.length() - 1);
      if (ch == '0' || ch == 'o') {
        //TODO consider the case B-\nA-B-C-B
        logWriter.append("Bad 0 at end of paragraph: " + para + "\n");
        para.delete(para.length() - 1, para.length());
        para.append('。');
        badEndZero++;
      }
      resultWriter.append(para + "\n");
      paraCount++;
    } catch (IOException e) {
    }

    para = new StringBuffer();
  }

  int badEndZero = 0;
  int lineEndDash = 0;
  int titleCount = 0;
  int paraCount = 0;

  protected void postProcess() throws IOException{
    logWriter.write("\n");
    logWriter.write("Total count of music: " + titleCount + "\n");
    logWriter.write("Total count of paragraph: " + paraCount + "\n");
    logWriter.write("Total replaced paragraph end ZERO: " + badEndZero + "\n");
    logWriter.write("Total removed line-end dash: " + lineEndDash + "\n");
  }

  public static void main(String[] args) throws IOException, URISyntaxException {

    StringBuffer sb = new StringBuffer();
    Pass2 p = new Pass2("a1.txt", "a2.txt");
    p.toString();
  }
}
